#pragma once
#include<iostream>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<memory>

#include"Log.hpp"
#include"InetAddr.hpp"




 
namespace socket_ns
{
    using namespace log_ns;
    class Socket; //类的声明
    using SockSPtr = std::shared_ptr<Socket>; //父类也用了 提到前面来

    const static int gblcklog = 8;

    enum
    {
        SOCKET_ERROR = -1,
        BIND_ERROR = -2,
        LISTEN_ERROR
    };

    //模板方法类模式
    class Socket //tcp
    {
    public:
        virtual void CreateSocketOrDie() = 0;
        virtual void CreateBindOrDie(uint16_t port) = 0;
        virtual void CreateListentOrDie(int blcklog = gblcklog) = 0;
        virtual SockSPtr Accepter(InetAddr *cliaddr) = 0;
        virtual bool Connector(const std::string &peerip, uint16_t peerport) = 0;
        virtual int Sockfd() = 0;
        virtual void Close() = 0;

        virtual ssize_t Recv(std::string *out) = 0;
        virtual int Send(const std::string &in) = 0;

    public:
        void BuildListenSocket(uint16_t port)
        {
            CreateSocketOrDie();
            CreateBindOrDie(port);
            CreateListentOrDie();
        }

        bool BuildClientSocket(const std::string &peerip, uint16_t peerport)
        {
            CreateSocketOrDie();
            return Connector(peerip, peerport);
           
        }
        // void BuildNormalSocket(){}
    };


    class TcpSocket : public Socket
    {
    public:
        TcpSocket()
        {}
        TcpSocket(int sockfd)
            :_sockfd(sockfd)
        {}
        ~TcpSocket()
        {}
        void CreateSocketOrDie() override
        {
             _sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
            if (_sockfd < 0)
            {
                LOG(FATAL, "socket create error \n");
                exit(SOCKET_ERROR);
            }

            LOG(INFO, "socket create sucess, sockfd : %d \n", _sockfd);
        }
        void CreateBindOrDie(uint16_t port) override
        {
            struct sockaddr_in local;
            memset(&local, 0, sizeof(local));
            local.sin_family = AF_INET;
            local.sin_port = htons(port);
            local.sin_addr.s_addr = INADDR_ANY;

            // 2. bind sockfd 和 Socket addr
            if (::bind(_sockfd, (struct sockaddr *)&local, sizeof(local)) < 0)
            {
                LOG(FATAL, "bind error\n");
                exit(BIND_ERROR);
            }
            LOG(INFO, "bind success, sockfd: %d\n", _sockfd); // 3
        }
        void CreateListentOrDie(int blcklog = gblcklog) override
        {
            if (::listen(_sockfd, blcklog) < 0)
            {
                LOG(FATAL, "listen error \n");
                exit(LISTEN_ERROR);
            }
            LOG(INFO, "listen success\n");
        }
        SockSPtr Accepter(InetAddr *cliaddr) override
        {
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            // 4.获取新连接
            int sockfd = ::accept(_sockfd, (struct sockaddr *)&client, &len);

            if (sockfd < 0)
            {
                LOG(WARNING, "accept error \n");
                return nullptr;
            }
            *cliaddr = InetAddr(client);
            //InetAddr addr(client);
            LOG(INFO, "get a new link, client info : %s \n", cliaddr->AddrStr().c_str());

            //因为又得到了 accept返回的文件描述符 我们也看作为一个套接字 需要返回的得到
            return std::make_shared<TcpSocket>(sockfd);//调用tcpsocket构造
        }
        bool Connector(const std::string &peerip, uint16_t peerport) override
        {
            struct sockaddr_in sever;
            memset(&sever, 0, sizeof(sever));
            sever.sin_family = AF_INET;
            sever.sin_port = htons(peerport);
            // sever.sin_addr.s_addr 字符串风格ip地址到网络序列
            ::inet_pton(AF_INET, peerip.c_str(), &sever.sin_addr);

            int n = ::connect(_sockfd, (const struct sockaddr *)&sever, sizeof(sever));
            if (n < 0)
            {
                return false;
            }

            return true;
        }   

        int Sockfd() override
        {
            return _sockfd;
        }
        void Close() override
        {
            if(_sockfd > 0)
                ::close(_sockfd);
        }

        ssize_t Recv(std::string *out) override
        {
                    
            char inbuffer[4096];
            ssize_t n = ::read(_sockfd, inbuffer, sizeof(inbuffer) - 1);
            if (n > 0)
            {
                inbuffer[n] = 0;
                *out += inbuffer;
            }

            return n;
        }
        
        int Send(const std::string &in) override
        {
            return ::send(_sockfd, in.c_str(), in.size(), 0);
        }

    private:
        int _sockfd; //可以是listen 可以是udpsocket
    };

    //模式
    // Socket* sock = new TcpSocket();
    // sock->BuildListenSocket();
    
    // class UdpSocket : public Socket
    // {};
} 
